from django_celery_beat.models import PeriodicTask, IntervalSchedule, CrontabSchedule, ClockedSchedule
from rest_framework import status
from rest_framework.permissions import IsAuthenticated
from rest_framework.views import APIView
from rest_framework.viewsets import ModelViewSet
from apps.system.serializers.schedules import TaskSerializer, IntervalSerializer, CrontabSerializer, ClockedSerializer
from conf.celery import app as celery_app
from rest_framework.response import Response
from apps.system.filter.schedules import SchedulesFilter
from rest_framework.exceptions import ParseError


class TaskList(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request):
        """
        获取注册任务列表
        """
        tasks = list(
            sorted(name for name in celery_app.tasks if not name.startswith('celery.')))
        return Response(tasks)


class TaskView(ModelViewSet):
    queryset = PeriodicTask.objects.exclude(name__contains='celery.')
    serializer_class = TaskSerializer
    # 自定义搜索
    filterset_class = SchedulesFilter

    def interval_save(self, data):
        """
        保存间隔数据，移除id方便插入新的数据
        规则如果有则采用之前的规则
        没有则新建
        此设计时为了保证数据更换规则之后不影响其他的数据
        """

        try:

            if 'id' in data:
                data.pop('id')

            is_interval = IntervalSchedule.objects.filter(**data).exists()
            if is_interval:
                interval = IntervalSchedule.objects.get(**data)
            else:
                interval, _ = IntervalSchedule.objects.get_or_create(**data, defaults=data)
            return interval
        except Exception as e:

            raise ParseError({'msg': '时间策略数据错误！'})

    def crontab_save(self, data):

        try:

            if 'id' in data:
                data.pop('id')

            is_crontab = CrontabSchedule.objects.filter(**data).exists()
            if is_crontab:
                crontab = CrontabSchedule.objects.get(**data)
            else:
                crontab, _ = CrontabSchedule.objects.get_or_create(**data, defaults=data)
            return crontab
        except Exception as e:
            print(e)
            raise ParseError({'msg': '时间策略数据错误！'})

    def clocked_save(self, data):

        try:

            if 'id' in data:
                data.pop('id')

            is_clocked = ClockedSchedule.objects.filter(**data).exists()
            if is_clocked:
                clocked = ClockedSchedule.objects.get(**data)
            else:
                clocked, _ = ClockedSchedule.objects.get_or_create(**data, defaults=data)
            return clocked
        except Exception as e:
            raise ParseError({'msg': '时间策略数据错误！'})

    def retrieve(self, request, *args, **kwargs):
        instance = self.get_object()
        serializer = self.get_serializer(instance)
        data = serializer.data
        if data['time_type'] == 'interval':
            data['interval_info'] = IntervalSerializer(
                IntervalSchedule.objects.filter(id=data['interval']).first()).data
        else:
            data['interval_info'] = {'every': 1, 'period': 'days'}

        if data['time_type'] == 'crontab':
            data['crontab_info'] = CrontabSerializer(CrontabSchedule.objects.filter(id=data['crontab']).first()).data
        else:
            data['crontab_info'] = {}

        if data['time_type'] == 'clocked':
            data['clocked_info'] = ClockedSerializer(ClockedSchedule.objects.filter(id=data['clocked']).first()).data
        else:
            data['clocked_info'] = {}
        return Response(data)

    def create(self, request, *args, **kwargs):
        data = request.data
        # return Response({'msg': '数据格式有误!'}, status=status.HTTP_400_BAD_REQUEST)
        # interval_info = data.get('interval_info', {})
        # crontab_info = data.get('crontab_info', {})
        print(data)

        if 'name' not in data:
            return Response({'msg': '请输入用户名称！'}, status=status.HTTP_400_BAD_REQUEST)
        elif 'task' not in data:
            return Response({'msg': '请输入任务名称！'}, status=status.HTTP_400_BAD_REQUEST)
        elif 'time_type' not in data or 'interval_info' not in data or 'crontab_info' not in data:
            return Response({'msg': '数据不正确!'}, status=status.HTTP_400_BAD_REQUEST)
        elif 'clocked_info' not in data:
            return Response({'msg': '数据不正确!'}, status=status.HTTP_400_BAD_REQUEST)

        if data['time_type'] == 'interval' and data['interval_info']:
            interval = self.interval_save(data['interval_info'])
            data['interval'] = interval.id

        if data['time_type'] == 'crontab' and data['crontab_info']:
            crontab = self.crontab_save(data['crontab_info'])
            data['crontab'] = crontab.id

        if data['time_type'] == 'clocked' and data['clocked_info']:
            clocked = self.clocked_save(data['clocked_info'])
            data['clocked'] = clocked.id

        serializer = self.get_serializer(data=data)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return Response({'msg': '成功！'}, status=status.HTTP_201_CREATED)

    def update(self, request, *args, **kwargs):
        data = request.data

        time_type = request.data.get('time_type')
        interval_info = request.data.get('interval_info')
        crontab_info = request.data.get('crontab_info')
        clocked_info = request.data.get('clocked_info')

        # 修改状态的判断，大于2是非状态修改
        if len(data) > 2:

            if time_type == 'interval' and interval_info:
                interval = self.interval_save(interval_info)
                data['interval'] = interval.id
                data['interval_info'] = IntervalSerializer(interval).data
            else:
                data['interval'] = None
                data['interval_info'] = {'every': 1, 'period': 'days'}

            if time_type == 'crontab' and crontab_info:
                crontab = self.crontab_save(crontab_info)
                data['crontab'] = crontab.id
            else:
                data['crontab'] = None

            if time_type == 'clocked' and clocked_info:
                clocked = self.clocked_save(clocked_info)
                data['clocked'] = clocked.id
            else:
                data['clocked'] = None

        partial = kwargs.pop('partial', False)
        instance = self.get_object()

        serializer = self.get_serializer(instance, data=data, partial=partial)
        serializer.is_valid(raise_exception=True)
        self.perform_update(serializer)

        if getattr(instance, '_prefetched_objects_cache', None):
            # If 'prefetch_related' has been applied to a queryset, we need to
            # forcibly invalidate the prefetch cache on the instance.
            instance._prefetched_objects_cache = {}

        return Response(data)
